﻿using System;
using System.Collections.Generic;

namespace Mars.GameCore
{
    /// <summary>
    /// 程序集相关的实用函数。
    /// </summary>
    public static class AssemblyUtility
    {
        private static readonly System.Reflection.Assembly[] SAssemblies = null;
        private static readonly Dictionary<string, Type> SCachedTypes = new (StringComparer.Ordinal);

        static AssemblyUtility()
        {
            SAssemblies = AppDomain.CurrentDomain.GetAssemblies();
        }

        /// <summary>
        /// 获取已加载的程序集。
        /// </summary>
        /// <returns>已加载的程序集。</returns>
        public static System.Reflection.Assembly[] GetAssemblies()
        {
            return SAssemblies;
        }


        /// <summary>
        /// 获取已加载的程序集中的所有类型。
        /// </summary>
        /// <returns>已加载的程序集中的所有类型。</returns>
        public static Type[] GetTypes()
        {
            List<Type> results = new List<Type>();
            foreach (System.Reflection.Assembly assembly in SAssemblies)
            {
                results.AddRange(assembly.GetTypes());
            }

            return results.ToArray();
        }

        /// <summary>
        /// 获取已加载的程序集中的所有类型。
        /// </summary>
        /// <param name="results">已加载的程序集中的所有类型。</param>
        public static void GetTypes(List<Type> results)
        {
            if (results == null)
            {
                throw new Exception("Results is invalid.");
            }

            results.Clear();
            foreach (System.Reflection.Assembly assembly in SAssemblies)
            {
                results.AddRange(assembly.GetTypes());
            }
        }

        /// <summary>
        /// 获取已加载的程序集中的指定类型。
        /// </summary>
        /// <param name="typeName">要获取的类型名。</param>
        /// <returns>已加载的程序集中的指定类型。</returns>
        public static Type GetType(string typeName)
        {
            if (string.IsNullOrEmpty(typeName))
            {
                throw new Exception("Type name is invalid.");
            }

            Type type = null;
            if (SCachedTypes.TryGetValue(typeName, out type))
            {
                return type;
            }

            type = Type.GetType(typeName);
            if (type != null)
            {
                SCachedTypes.Add(typeName, type);
                return type;
            }

            foreach (System.Reflection.Assembly assembly in SAssemblies)
            {
                type = Type.GetType($"{typeName}, {assembly.FullName}");
                if (type != null)
                {
                    SCachedTypes.Add(typeName, type);
                    return type;
                }
            }

            return null;
        }

        /// <summary>
        /// 获取已加载的程序集中的指定类型的子类列表。
        /// </summary>
        /// <param name="type">指定类型</param>
        /// <returns></returns>
        public static List<string> GetRuntimeTypeNames(Type type)
        {
            var types = GetTypes();
            List<string> results = new List<string>();
            foreach (var t in types)
            {
                if (t.IsAbstract || !t.IsClass)
                {
                    continue;
                }

                if (t.IsSubclassOf(type) || t.IsImplWithInterface(type))
                {
                    results.Add(t.FullName);
                }
            }

            return results;
        }
    }
}